/*   Carina
 *   Copyright (C) 2009 2010 2011  Zdravko Velinov
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _SCENE_EXPLORER_HH_
#define _SCENE_EXPLORER_HH_

#include <QDockWidget>
#include <QAbstractListModel>

#include "ui_scene-explorer.h"
#include "property-editor.hh"

#include "carina/common/containers.hh"
#include "carina/common/ces-file.hh"
#include "carina/node-manager.hh"
#include "carina/lighting.hh"
#include "carina/scene.hh"

using namespace Carina;

class GLSModel: public QAbstractListModel
{
    Q_OBJECT

    enum
    {
        LIGHT_SOURCE_TYPE,
        ATTR_COUNT
    };

    ScenePtr                m_Scene;
    CESGlobalLightSection&  m_GLightSection;
    LightingManagerPtr      m_LightMgr;
public:
    GLSModel(CESGlobalLightSection& glight_section, const LightingManagerPtr& lmgr, const ScenePtr& scene);

    virtual int rowCount(const QModelIndex& parent=QModelIndex()) const;
    virtual QVariant data(const QModelIndex& index, int role) const;

    EditablePtr getEditable(const QModelIndex& index);

    virtual bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
    virtual bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());

    bool insertRow(const string& lstype, const GlobalLightSourcePtr& gls);

    bool reload();
    void clear();
};

class STNode
{
    CESNode&                m_CESNode;
    NodePtr                 m_CarinaNode;
    DynamicArray<STNode*>   m_Children;
    STNode                  *m_Parent;

public:
    STNode(STNode* _parent, CESNode& _ces_node, const NodePtr& _carina_node);
     ~STNode();

    STNode* getParent();
    size_t getIndex(STNode* child);

    size_t getChildrenCount();
    STNode& getChild(size_t idx);
    void deleteChildren(size_t lhs, size_t rhs);
    void addChild(CESNode& _ces_node, const NodePtr& _carina_node);
    void clear();

    CESNode& getCESNode();
    NodePtr getCarinaNode();
};

inline STNode& STNodeReference(const QModelIndex& model_index) { return *static_cast<STNode*>(model_index.internalPointer()); }

class SceneTreeModel: public QAbstractItemModel
{
    Q_OBJECT

    enum
    {
        NODE_TYPE,
        ATTR_COUNT
    };

    STNode                  m_Root;

    ScenePtr                m_Scene;
    NodeManagerPtr          m_NodeMgr;
public:
    SceneTreeModel(CESFile& ces_file, const NodeManagerPtr& nmgr, const ScenePtr& scene);

    virtual QModelIndex parent(const QModelIndex& index) const;
    virtual QModelIndex index(int row, int column, const QModelIndex& parent=QModelIndex()) const;
    virtual QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const;
    
    EditablePtr getEditable(const QModelIndex& index);

    virtual int rowCount(const QModelIndex & parent=QModelIndex()) const;
    virtual int columnCount(const QModelIndex & parent=QModelIndex()) const;

    virtual bool insertRows(int row, int count, const QModelIndex& parent=QModelIndex());
    virtual bool removeRows(int row, int count, const QModelIndex& parent=QModelIndex());

    bool insertRow(const string& node_type, const string& creation_data, const NodePtr& carina_node, const QModelIndex& index=QModelIndex());
    
    bool insertNode(const QModelIndex& parent=QModelIndex());

    bool reload();
    void clear();
};

class SceneExplorer: public QDockWidget
{
    Q_OBJECT

    Ui::SceneExplorer       m_SceneExp;

    SceneTreeModel          m_STModel;
    GLSModel                m_GLSModel;

    CESFile&                m_CESFile;
    ScenePtr                m_Scene;
    NodeManagerPtr          m_NodeMgr;
    LightingManagerPtr      m_LightMgr;
    EditablePtr             m_CurrentEditable;
public:
    SceneExplorer(CESFile& ces_file, const LightingManagerPtr& lmgr, const NodeManagerPtr& nmgr, const ScenePtr& scene);

    bool reload();
    void clear();

public slots:
    void createLightSource(const string& lstype);
    void createModelInstance(const string& model_inst);

private:
    QModelIndex getSelected();

signals:
    void editableSelected(const EditablePtr& editable);

private slots:
    void on_AddNode_clicked(bool checked);
    void on_DeleteObject_clicked(bool checked);
    void on_AmbientColorPicker_clicked();

    void on_SceneTree_clicked(const QModelIndex& index);
    void on_GlobalLightList_clicked(const QModelIndex& index);
    void on_GlobalLightList_customContextMenuRequested(const QPoint& pos);
};

#endif /* _SCENE_EXPLORER_HH_ */